package org.zhuzx.util.pool;

import java.lang.reflect.Array;
import java.util.concurrent.atomic.AtomicInteger;

import org.zhuzx.util.MicroUtil;

//@Deprecated//get方法的多样化（需要实现阻塞），以及等待继承实现动态容量、自动清理、自动活跃。
/*
 * 一级：固定容量，用于严格场合如ByteBuffer（阻塞， IO并发有负面影响，必须限制数量，当然是否应该始终保持存活还有待商榷）
 * 		无谓场合如DateFormat（新增，仅为争取提升速度）
 * 二级：动态容量，弱引用，随GC回收，出发点是尽可能多地存储备用，如char[]
 * 三级：动态容量，自动清理，自动活跃，用于代价最高昂的对象，需要尽可能地缩小数量，如网络连接
 */
public abstract class AbstractFixedPool<E> {
	
	private static final int READY = 1;
	private static final int USING = 0;
	
	private StatefulItem<E>[] items;
	private ImmutableIdentityMap<E,AtomicInteger> mapping;//不可使用Hash系列的容器，因其依赖于key的hashCode方法。
	private AtomicInteger cursor = new AtomicInteger(-1);
	private int lastIndex;
	private int maxSize;
	private AtomicInteger size;
	
	private static class StatefulItem<E> {
		E originalItem;
		AtomicInteger flag;//AtomicBoolean的内部实现也是AtomicInteger
		
		StatefulItem(E e) {
			originalItem = e;
			flag = new AtomicInteger(READY);
		}
	}
	
	protected AbstractFixedPool(int size) {
		if (size <= 0) {
			throw new IllegalArgumentException("size必须大于0");
		}
		@SuppressWarnings("unchecked")
		StatefulItem<E>[] temp = new StatefulItem[size];
		items = temp;
		for (int i=0; i<size; i++) {
			items[i] = new StatefulItem<E>(create());
		}
		@SuppressWarnings("unchecked")
		E[] originalItems = (E[]) Array.newInstance(items[0].originalItem.getClass(), size);
		AtomicInteger[] flags = new AtomicInteger[size];
		for (int i=0; i<size; i++) {
			originalItems[i] = items[i].originalItem;
			flags[i] = items[i].flag;
		}
		mapping = new ImmutableIdentityMap<>(originalItems, flags);
		this.lastIndex = size - 1;
		this.maxSize = size;
		this.size = new AtomicInteger(size);
	}
	
	protected abstract E create();
	
	protected E tryGet() {
		int start = MicroUtil.increaseInCycle(cursor.get(), lastIndex);
		int i = start;
		do {
			StatefulItem<E> item = items[i];
			AtomicInteger flag = item.flag;
			if (flag.get() == READY) {
				if (flag.compareAndSet(READY, USING)) {
					size.decrementAndGet();
					cursor.set(i);//游标只为提升效率，不严格要求正确性，容忍被其它线程覆盖设值。
					return item.originalItem;
				}
			}
			i = MicroUtil.increaseInCycle(i, lastIndex);
		} while (i != start);
		return null;
	}
	
	public E get() {
		if (size.get() > 0) {
			E e = tryGet();
			return e==null ? create() : e;
		} else {
			return create();
		}
	}
	
	public boolean giveBack(E e) {
		if (size.get() == maxSize) return false;
		AtomicInteger flag = mapping.get(e);
		if (flag == null) {
			return false;
		} else if (flag.get() == READY) {//这个判断仅测试阶段使用，可去除。
			throw new RuntimeException("concurrent error");
		} else {
			flag.set(READY);
			size.incrementAndGet();
			return true;
		}
	}
	
	public int size() {
		return size.get();
	}
	
}